
#pragma once

#include "..\\ExternalTools\\ExternalTools.h"

#include "..\\Loirey\\loirey_GLOBAL.h"
#include "..\\Loirey\\loirey_MyMath.h"
#include "..\\Loirey\\loirey_BasicStructure.h"

using namespace loirey;

class C_TRSable_Image
{
public:
	static const int EXPANDING_MODE_COLOR = 0;
	static const int EXPANDING_MODE_TILE = 1;
	static const int EXPANDING_MODE_EDGE = 2;
public:
	class CParameters
	{
	protected:
		double _cos_ra1, _sin_ra1;
		double _cos_ra2, _sin_ra2;
		double _rv_xs, _rv_ys;
	public:
		double xOldCenter, xScale, xNewCenter;
		double yOldCenter, yScale, yNewCenter;
		double RotatingAngle_BEFORE_Rescaling;
		double RotatingAngle_AFTER_Rescaling;
	public:
		CParameters()
		{
			myInit(
				0.0, 0.0,
				0.0, 0.0,
				1.0, 1.0,
				0.0,
				0.0
				);
		}
		void myInit(
			double xOldCenter, double yOldCenter,
			double xNewCenter, double yNewCenter,
			double xScale, double yScale,
			double RotatingAngle_BEFORE_Rescaling,
			double RotatingAngle_AFTER_Rescaling
			);
		void ComputeNewPosition(double& DstNewX, double& DstNewY, double xSrc, double ySrc) const;
		void ComputeSourcePosition(double& DstXonSource, double& DstYonSource, double xNew, double yNew) const;
	};
protected:
	CImg<double> _imgSrc;
public:
	int W, H, WH, V;
	CSimpleTypeArray<double> DefaultColor;

public:
	double GetPixel(double x, double y, int v, int ExpandingMode);

	size_t GetMemoryUsage() const
	{
		return sizeof(int) * 4 + CExternalTools::GetMemoryUsage(_imgSrc) + DefaultColor.GetMemoryUsage();
	}

	C_TRSable_Image()
	{
		W = H = -1; V = 0;
	}

	template<typename T>
	void myInit(const CImg<T>& imgSource, int z = 0)
	{

		W = imgSource.dimx();
		H = imgSource.dimy();
		V = imgSource.dimv();

		WH = W * H;
		_imgSrc.assign(imgSource, false);

		//_W1 = W + 1;
		//_H1 = H + 1;

		//int i,ix,iy,iv;
		//int xa,xb,ya,yb;

		//_W1H1 = _W1*_H1; _W1H1V = _W1H1*V;
		//imgSrc.assign(_W1,_H1,1,V);
		//for ( i = 0; i < _W1H1V; ++i )
		//{
		//	ix = i%_W1;
		//	iy = i%_W1H1/_W1;
		//	iv = i/_W1H1;

		//	xa = (ix>0 ? ix-1 : 0);
		//	xb = (ix<W ? ix : W-1);
		//	ya = (iy>0 ? iy-1 : 0);
		//	yb = (iy<H ? iy : H-1);

		//	imgSrc.at(ix,iy,0,iv) = 0.25 * (
		//		(double)(imgSource.at(xa, ya, z, iv)) +
		//		(double)(imgSource.at(xa, yb, z, iv)) +
		//		(double)(imgSource.at(xb, ya, z, iv)) +
		//		(double)(imgSource.at(xb, yb, z, iv)) +
		//		0.0);
		//}

		DefaultColor.Resize(V);
		DefaultColor.Fill(0.0);
	}

	void myInit(string strFN_SourceImage_IntRGB)
	{
		CImg<int> imgTmp;
		CExternalTools::myLoadImage(strFN_SourceImage_IntRGB, imgTmp);
		myInit(imgTmp);
	}

	template<typename T>
	void BuildImage(CImg<T>& imgDestination, int Width, int Height, const CParameters& Parameters, int ExpandingMode, int v = -1)
	{
		int iv_base, iv_amount, iv, iv_real, ix, iy;
		double tx,ty,t;
		T *pd;

		if (v<0 || v>=V)
		{
			iv_amount = V;
			iv_base = 0;
		}
		else
		{
			iv_amount = 1;
			iv_base = v;
		}

		imgDestination.assign(Width, Height, 1, iv_amount);
		pd = imgDestination.data;
		for ( iv = 0; iv < iv_amount; ++iv )
		{
			iv_real = iv_base + iv;
			for ( iy = 0; iy < Height; ++iy ) for ( ix = 0; ix < Width; ++ix )
			{
				Parameters.ComputeSourcePosition(tx, ty, ix + 0.5, iy + 0.5);
				t = GetPixel(tx, ty, iv_real, ExpandingMode);
				*(pd++) = CMyMath::TranslateNumber_Round(t, (T)0);
			}
		}
	}
};

class CImagePositionQueryAnswerer
{
public:
	class CPixRef
	{
	public:
		int index;
		int x, y;

	public:
		static bool CompareBy_X_Y(const CPixRef& a, const CPixRef& b);
	};

public:
	static const int DISTANCE_MODE_EUCLID = 0;
	static const int DISTANCE_MODE_MANHATTAN = 1;

public:
	int W, H;
	int PixelAmount;
	int DistanceMode;

public:
	CSimpleTypeArray<CPixRef> PixRefList;
	int X_Amount;
	CSimpleTypeArray<const CPixRef*> X_PtrList;

protected:
	static const CPixRef* _MySearch_Y(const CPixRef* Hd, const CPixRef* Tl, int KeyY);
public:
	int ComputePixelDistance(int dx, int dy) const;
public:
	CImagePositionQueryAnswerer();
	virtual size_t GetMemoryUsage() const;
public:
	void myInit(int W, int H, const CSimpleTypeArray<int>& PixelList, int DistanceMode);
	const CPixRef* FindNearestSampledPixel(int SrcPixelXY) const;
	const CPixRef* FindNearestSampledPixel(int SrcX, int SrcY) const;
};

//class CScalableImage
//{
//public:
//	class CScaleConfig
//	{
//	public:
//		double LnScaleX;
//		double ScaleX;
//		double LnScaleY;
//		double ScaleY;
//		double fW;
//		double fH;
//		int iW;
//		int iH;
//	};
//	class CPositionOnImage
//	{
//	public:
//		int ix,iy;
//		double dx,dy;
//	};
//
//protected:
//	int W1, H1, W1H1, W1H1V;
//	CImg<double> imgSrc;
//public:
//	int W, H, V;
//	CScaleConfig DefaultScale;
//
//public:
//	template<typename T>
//	void myInit(const CImg<T>& imgSource)
//	{
//		int i,ix,iy,iv;
//		int xa,xb,ya,yb;
//
//		W = imgSource.dimx(); W1 = W + 1;
//		H = imgSource.dimy(); H1 = H + 1;
//		V = imgSource.dimv();
//		W1H1 = W1*H1; W1H1V = W1H1*V;
//		imgSrc.assign(W1,H1,1,V);
//		for ( i = 0; i < W1H1V; ++i )
//		{
//			ix = i%W1;
//			iy = i%W1H1/W1;
//			iv = i/W1H1;
//
//			xa = (ix>0 ? ix-1 : 0);
//			xb = (ix<W ? ix : W-1);
//			ya = (iy>0 ? iy-1 : 0);
//			yb = (iy<H ? iy : H-1);
//
//			imgSrc.at(ix,iy,0,iv) = 0.25 * (
//				(double)(imgSource.at(xa, ya, 0, iv)) +
//				(double)(imgSource.at(xa, yb, 0, iv)) +
//				(double)(imgSource.at(xb, ya, 0, iv)) +
//				(double)(imgSource.at(xb, yb, 0, iv)) +
//				0.0);
//		}
//		BuildScaleConfig(DefaultScale);
//	}
//
//	
//	void BuildScaleConfig(CScaleConfig& dstScaleConfig, double LnScale = 0.0);
//	void BuildScaleConfig(CScaleConfig& dstScaleConfig, double LnScaleX, double LnScaleY);
//	void BuildScaleConfig_i(CScaleConfig& dstScaleConfig, int iWidth, int iHeight);
//
//	void BuildOriginalPosition_real(CPositionOnImage& dstPosition, double real_x, double real_y);
//	void BuildOriginalPosition_pixel(CPositionOnImage& dstPosition, int pixel_x, int pixel_y);
//	void BuildOriginalPosition_fraction(CPositionOnImage& dstPosition, double fraction_x, double fraction_y);
//
//	void BuildOriginalPosition_real(CPositionOnImage& dstPosition, double real_x, double real_y, const CScaleConfig& ScaleConfig);
//	void BuildOriginalPosition_pixel(CPositionOnImage& dstPosition, int pixel_x, int pixel_y, const CScaleConfig& ScaleConfig);
//	void BuildOriginalPosition_fraction(CPositionOnImage& dstPosition, double fraction_x, double fraction_y, const CScaleConfig& ScaleConfig);
//
//	void BuildNewPosition_real(CPositionOnImage& dstPosition, double real_x, double real_y, const CScaleConfig& ScaleConfig);
//	void BuildNewPosition_pixel(CPositionOnImage& dstPosition, int pixel_x, int pixel_y, const CScaleConfig& ScaleConfig);
//	void BuildNewPosition_fraction(CPositionOnImage& dstPosition, double fraction_x, double fraction_y, const CScaleConfig& ScaleConfig);
//
//	double GetPixelValue(const CPositionOnImage& OriginalPosition, int v = 0);
//
//	template<typename T>
//	void BuildImage(CImg<T>& imgDestination, const CScaleConfig& ScaleConfig)
//	{
//		CPositionOnImage OriginalPosition;
//		int ix,iy,iv;
//		double t;
//		T* pd;
//
//		imgDestination.assign(ScaleConfig.iW, ScaleConfig.iH, 1, V);
//		pd = imgDestination.data;
//		for ( iv = 0; iv < V; ++iv ) for ( iy = 0; iy < ScaleConfig.iH; ++iy ) for ( ix = 0; ix < ScaleConfig.iW; ++ix )
//		{
//			BuildOriginalPosition_pixel(OriginalPosition, ix, iy, ScaleConfig);
//			t = GetPixelValue(OriginalPosition, iv);
//			*(pd++) = CMyMath::TranslateNumber_Round(t, (T)0);
//		}
//	}
//
//	template<typename T>
//	void BuildImage_v(CImg<T>& imgDestination, const CScaleConfig& ScaleConfig, int v)
//	{
//		CPositionOnImage OriginalPosition;
//		int ix,iy;
//		T* pd;
//
//		imgDestination.assign(ScaleConfig.iW, ScaleConfig.iH, 1, 1);
//		pd = imgDestination.data;
//		for ( iy = 0; iy < ScaleConfig.iH; ++iy ) for ( ix = 0; ix < ScaleConfig.iW; ++ix )
//		{
//			BuildOriginalPosition_pixel(OriginalPosition, ix, iy, ScaleConfig);
//			t = GetPixelValue(OriginalPosition, v);
//			*(pd++) = CMyMath::TranslateNumber_Round(t, (T)0);
//		}
//	}
//};

